using System;
using System.IO;
using CodePlex.TfsLibrary.ObjectModel;
using CodePlex.TfsLibrary.RepositoryWebSvc;
using Xunit;

namespace CodePlex.TfsLibrary.ClientEngine
{
    public class TfsEngineUpdateTest
    {
        static SourceItem root = SourceItem.FromItem(1, ItemType.Folder,
                                                     SourceItemStatus.Unmodified, SourceItemStatus.Unmodified, @"C:\Foo", null, 2, 0, null,
                                                     SourceItemStatus.Unmodified, "$/Foo", 2, null);

        public class Update
        {
            [Fact]
            public void CallsStatusWithServer()
            {
                VersionSpec version = VersionSpec.FromChangeset(42);
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 1, SourceItemStatus.Unmodified);
                engine.StubStatusWithServer();

                engine.Update(@"C:\Foo", true, version, delegate {});

                Assert.Equal(@"C:\Foo", engine.StatusWithServer_LocalPath);
                Assert.Same(version, engine.StatusWithServer_Version);
                Assert.True(engine.StatusWithServer_Recursive);
            }

            [Fact]
            public void DirectoryNotUnderSourceControl()
            {
                SourceItem callbackItem = null;
                UpdateAction callbackAction = UpdateAction.None;
                SourceItemResult callbackResult = SourceItemResult.S_Ok;
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");

                engine.Update(@"C:\Foo", true, VersionSpec.Latest, delegate(SourceItem item,
                                                                            UpdateAction actionTaken,
                                                                            SourceItemResult result)
                                                                   {
                                                                       Assert.Null(callbackItem); // Single callback
                                                                       callbackItem = item;
                                                                       callbackAction = actionTaken;
                                                                       callbackResult = result;
                                                                   });

                Assert.Equal(@"C:\Foo", callbackItem.LocalName);
                Assert.Equal(UpdateAction.None, callbackAction);
                Assert.Equal(SourceItemResult.E_NotUnderSourceControl, callbackResult);
            }

            [Fact]
            public void NoServerChanges()
            {
                VersionSpec version = VersionSpec.Latest;
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 2, SourceItemStatus.Unmodified);
                engine.StubStatusWithServer(root);

                engine.Update(@"C:\Foo", false, version, delegate
                                                         {
                                                             throw new InvalidOperationException("Should not be called back");
                                                         });
            }

            [Fact]
            public void NullLocalPath()
            {
                TestableTfsEngine engine = TestableTfsEngine.Create();

                Assert.Throws<ArgumentNullException>(delegate
                                                     {
                                                         engine.Update(null, true, VersionSpec.Latest, null);
                                                     });
            }

            [Fact]
            public void NullVersion()
            {
                TestableTfsEngine engine = TestableTfsEngine.Create();

                Assert.Throws<ArgumentNullException>(delegate
                                                     {
                                                         engine.Update(@"C:\Foo", true, null, null);
                                                     });
            }

            [Fact]
            public void PathNotFound()
            {
                SourceItem callbackItem = null;
                UpdateAction callbackAction = UpdateAction.None;
                SourceItemResult callbackResult = SourceItemResult.S_Ok;
                TestableTfsEngine engine = TestableTfsEngine.Create();

                engine.Update(@"C:\Foo", true, VersionSpec.Latest, delegate(SourceItem item,
                                                                            UpdateAction actionTaken,
                                                                            SourceItemResult result)
                                                                   {
                                                                       callbackItem = item;
                                                                       callbackAction = actionTaken;
                                                                       callbackResult = result;
                                                                   });

                Assert.Equal(@"C:\Foo", callbackItem.LocalName);
                Assert.Equal(UpdateAction.None, callbackAction);
                Assert.Equal(SourceItemResult.E_NotUnderSourceControl, callbackResult);
            }

            [Fact]
            public void SubDirectoryDeleted()
            {
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.EnsurePath(@"C:\Foo\Baz");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 1, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo/Baz", @"C:\Foo\Baz", 1, 1, SourceItemStatus.Delete);
                engine.StubStatusWithServer(SourceItem.FromLocalItem(1, ItemType.Folder, SourceItemStatus.Unmodified, SourceItemStatus.Unmodified,
                                                                     @"C:\Foo", null, 1, 0, null),
                                            SourceItem.FromLocalItem(1, ItemType.Folder, SourceItemStatus.Delete, SourceItemStatus.Delete,
                                                                     @"C:\Foo\Baz", null, 1, 0, null));

                engine.Update(@"C:\Foo", true, VersionSpec.Latest, delegate
                                                                   {
                                                                       throw new InvalidOperationException("Should not be called back");
                                                                   });
            }

            [Fact]
            public void SubDirectoryNotUnderSourceControl()
            {
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 1, SourceItemStatus.Unmodified);
                engine.StubStatusWithServer(SourceItem.FromLocalDirectory(1, SourceItemStatus.Unmodified, SourceItemStatus.Unmodified, @"C:\Foo", 1),
                                            SourceItem.FromLocalDirectory(0, SourceItemStatus.Unversioned, SourceItemStatus.Unversioned, @"C:\Foo\Baz", 0));

                engine.Update(@"C:\Foo", true, VersionSpec.Latest, delegate
                                                                   {
                                                                       throw new InvalidOperationException("Should not be called back");
                                                                   });
            }

            [Fact]
            public void ValidatesDirectoryStructure()
            {
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 1, SourceItemStatus.Unmodified);
                engine.StubStatusWithServer();

                engine.Update(@"C:\Foo", true, VersionSpec.Latest, delegate {});

                Assert.Equal(@"C:\Foo", engine.ValidateDirectoryStructure_Directory);
            }
        }

        public class Update_File_ServerAdd
        {
            [Fact]
            public void DownloadedAndTracked()
            {
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 2, SourceItemStatus.Unmodified);
                engine.StubStatusWithServer(root,
                                            SourceItem.FromItem(3, ItemType.File,
                                                                SourceItemStatus.None, SourceItemStatus.None, @"C:\Foo\bar.txt", null, 0, 0, null,
                                                                SourceItemStatus.Add, "$/Foo/bar.txt", 4, "dt"));

                engine.Update(@"C:\Foo", false, VersionSpec.Latest, null);

                Assert.True(engine.FileSystem.FileExists(@"C:\Foo\bar.txt"));
                Assert.True(engine.TfsState.IsFileTracked(@"C:\Foo\bar.txt"));
            }

            [Fact]
            public void LocalAdded()
            {
                SourceItem callbackItem = null;
                UpdateAction callbackAction = UpdateAction.Deleted;
                SourceItemResult callbackResult = SourceItemResult.S_Ok;
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.WriteAllText(@"C:\Foo\bar.txt", "bar.txt");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 2, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFile(@"C:\Foo\bar.txt", 0, 0, SourceItemStatus.Add);
                engine.StubStatusWithServer(root,
                                            SourceItem.FromItem(3, ItemType.File,
                                                                SourceItemStatus.Add, SourceItemStatus.Add, @"C:\Foo\bar.txt", null, 0, 0, null,
                                                                SourceItemStatus.Add, "$/Foo/bar.txt", 4, "dt"));

                engine.Update(@"C:\Foo", false, VersionSpec.Latest, delegate(SourceItem item,
                                                                             UpdateAction actionTaken,
                                                                             SourceItemResult result)
                                                                    {
                                                                        callbackItem = item;
                                                                        callbackAction = actionTaken;
                                                                        callbackResult = result;
                                                                    });

                Assert.Equal(SourceItemStatus.Add, callbackItem.LocalItemStatus);
                Assert.Equal(SourceItemStatus.Add, callbackItem.RemoteItemStatus);
                Assert.Equal(UpdateAction.None, callbackAction);
                Assert.Equal(SourceItemResult.E_WontClobberLocalItem, callbackResult);
            }

            [Fact]
            public void LocalNotPresent()
            {
                SourceItem callbackItem = null;
                UpdateAction callbackAction = UpdateAction.None;
                SourceItemResult callbackResult = SourceItemResult.S_Ok;
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 2, SourceItemStatus.Unmodified);
                engine.StubStatusWithServer(root,
                                            SourceItem.FromItem(3, ItemType.File,
                                                                SourceItemStatus.None, SourceItemStatus.None, @"C:\Foo\bar.txt", null, 0, 0, null,
                                                                SourceItemStatus.Add, "$/Foo/bar.txt", 4, "dt"));

                engine.Update(@"C:\Foo", false, VersionSpec.Latest, delegate(SourceItem item,
                                                                             UpdateAction actionTaken,
                                                                             SourceItemResult result)
                                                                    {
                                                                        callbackItem = item;
                                                                        callbackAction = actionTaken;
                                                                        callbackResult = result;
                                                                    });

                Assert.Equal(SourceItemStatus.None, callbackItem.LocalItemStatus);
                Assert.Equal(SourceItemStatus.Add, callbackItem.RemoteItemStatus);
                Assert.Equal(UpdateAction.Added, callbackAction);
                SourceItem resultItem = engine.TfsState.GetSourceItem(@"C:\Foo\bar.txt");
                Assert.Equal(3, resultItem.ItemId);
                Assert.Equal(ItemType.File, resultItem.ItemType);
                Assert.Equal(4, resultItem.LocalChangesetId);
                Assert.Equal(SourceItemStatus.Unmodified, resultItem.LocalItemStatus);
                Assert.Equal(@"C:\Foo\bar.txt", resultItem.LocalName);
                Assert.Equal(SourceItemResult.S_Ok, callbackResult);
            }

            [Fact]
            public void LocalUnversioned()
            {
                SourceItem callbackItem = null;
                UpdateAction callbackAction = UpdateAction.Deleted;
                SourceItemResult callbackResult = SourceItemResult.S_Ok;
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.WriteAllText(@"C:\Foo\bar.txt", "bar.txt");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 2, SourceItemStatus.Unmodified);
                engine.StubStatusWithServer(root,
                                            SourceItem.FromItem(3, ItemType.File,
                                                                SourceItemStatus.Unversioned, SourceItemStatus.Unversioned, @"C:\Foo\bar.txt", null, 0, 0, null,
                                                                SourceItemStatus.Add, "$/Foo/bar.txt", 4, "dt"));

                engine.Update(@"C:\Foo", false, VersionSpec.Latest,
                              delegate(SourceItem item,
                                       UpdateAction actionTaken,
                                       SourceItemResult result)
                              {
                                  callbackItem = item;
                                  callbackAction = actionTaken;
                                  callbackResult = result;
                              });

                Assert.Equal(SourceItemStatus.Unversioned, callbackItem.LocalItemStatus);
                Assert.Equal(SourceItemStatus.Add, callbackItem.RemoteItemStatus);
                Assert.Equal(UpdateAction.None, callbackAction);
                Assert.Equal(SourceItemResult.E_WontClobberLocalItem, callbackResult);
            }
        }

        public class Update_File_ServerDelete
        {
            [Fact]
            public void LocalConflict()
            {
                SourceItem callbackItem = null;
                UpdateAction callbackAction = UpdateAction.None;
                SourceItemResult callbackResult = SourceItemResult.S_Ok;
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.WriteAllText(@"C:\Foo\bar.txt", "text");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 2, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFile(@"C:\Foo\bar.txt", 3, 4, SourceItemStatus.Unmodified);
                engine.TfsState.MarkFileAsConflicted(@"C:\Foo\bar.txt", @"C:\Foo\bar.txt", 5);
                engine.StubStatusWithServer(root,
                                            SourceItem.FromItem(3, ItemType.File,
                                                                SourceItemStatus.Conflict, SourceItemStatus.Conflict, @"C:\Foo\bar.txt", null, 4, 5, null,
                                                                SourceItemStatus.Delete, "$/Foo/bar.txt", 0, null));

                engine.Update(@"C:\Foo", false, VersionSpec.Latest, delegate(SourceItem item,
                                                                             UpdateAction actionTaken,
                                                                             SourceItemResult result)
                                                                    {
                                                                        callbackItem = item;
                                                                        callbackAction = actionTaken;
                                                                        callbackResult = result;
                                                                    });

                Assert.Equal(SourceItemStatus.Conflict, callbackItem.LocalItemStatus);
                Assert.Equal(SourceItemStatus.Delete, callbackItem.RemoteItemStatus);
                Assert.Equal(UpdateAction.None, callbackAction);
                SourceItem resultItem = engine.GetSourceItem(@"C:\Foo\bar.txt");
                Assert.Equal(SourceItemStatus.Conflict, resultItem.LocalItemStatus);
                Assert.Equal(4, resultItem.LocalChangesetId);
                Assert.Equal(5, resultItem.LocalConflictChangesetId);
                Assert.Equal(SourceItemResult.E_WontDeleteFileWithModifications, callbackResult);
            }

            [Fact]
            public void LocalDelete()
            {
                SourceItem callbackItem = null;
                UpdateAction callbackAction = UpdateAction.None;
                SourceItemResult callbackResult = SourceItemResult.S_Ok;
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 2, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFile(@"C:\Foo\bar.txt", 3, 4, SourceItemStatus.Delete);
                engine.StubStatusWithServer(root,
                                            SourceItem.FromItem(3, ItemType.File,
                                                                SourceItemStatus.Delete, SourceItemStatus.Delete, @"C:\Foo\bar.txt", null, 4, 0, null,
                                                                SourceItemStatus.Delete, "$/Foo/bar.txt", 0, null));

                engine.Update(@"C:\Foo", false, VersionSpec.Latest, delegate(SourceItem item,
                                                                             UpdateAction actionTaken,
                                                                             SourceItemResult result)
                                                                    {
                                                                        callbackItem = item;
                                                                        callbackAction = actionTaken;
                                                                        callbackResult = result;
                                                                    });

                Assert.Equal(SourceItemStatus.Delete, callbackItem.LocalItemStatus);
                Assert.Equal(SourceItemStatus.Delete, callbackItem.RemoteItemStatus);
                Assert.Equal(UpdateAction.Deleted, callbackAction);
                Assert.False(engine.FileSystem.FileExists(@"C:\Foo\bar.txt"));
                Assert.False(engine.TfsState.IsFileTracked(@"C:\Foo\bar.txt"));
                Assert.Equal(SourceItemResult.S_Ok, callbackResult);
            }

            [Fact]
            public void LocalMissing()
            {
                SourceItem callbackItem = null;
                UpdateAction callbackAction = UpdateAction.None;
                SourceItemResult callbackResult = SourceItemResult.S_Ok;
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.WriteAllText(@"C:\Foo\bar.txt", "the file text");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 2, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFile(@"C:\Foo\bar.txt", 3, 4, SourceItemStatus.Unmodified);
                engine.FileSystem.DeleteFile(@"C:\Foo\bar.txt");
                engine.StubStatusWithServer(root,
                                            SourceItem.FromItem(3, ItemType.File,
                                                                SourceItemStatus.Missing, SourceItemStatus.Unmodified, @"C:\Foo\bar.txt", null, 4, 0, null,
                                                                SourceItemStatus.Delete, "$/Foo/bar.txt", 0, null));

                engine.Update(@"C:\Foo", false, VersionSpec.Latest, delegate(SourceItem item,
                                                                             UpdateAction actionTaken,
                                                                             SourceItemResult result)
                                                                    {
                                                                        callbackItem = item;
                                                                        callbackAction = actionTaken;
                                                                        callbackResult = result;
                                                                    });

                Assert.Equal(SourceItemStatus.Missing, callbackItem.LocalItemStatus);
                Assert.Equal(SourceItemStatus.Delete, callbackItem.RemoteItemStatus);
                Assert.Equal(UpdateAction.Deleted, callbackAction);
                Assert.False(engine.FileSystem.FileExists(@"C:\Foo\bar.txt"));
                Assert.False(engine.TfsState.IsFileTracked(@"C:\Foo\bar.txt"));
                Assert.Equal(SourceItemResult.S_Ok, callbackResult);
            }

            [Fact]
            public void LocalModified()
            {
                SourceItem callbackItem = null;
                UpdateAction callbackAction = UpdateAction.None;
                SourceItemResult callbackResult = SourceItemResult.S_Ok;
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.WriteAllText(@"C:\Foo\bar.txt", "text");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 2, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFile(@"C:\Foo\bar.txt", 3, 4, SourceItemStatus.Unmodified);
                engine.FileSystem.WriteAllText(@"C:\Foo\bar.txt", "modified text");
                engine.StubStatusWithServer(root,
                                            SourceItem.FromItem(3, ItemType.File,
                                                                SourceItemStatus.Modified, SourceItemStatus.Modified, @"C:\Foo\bar.txt", null, 4, 0, null,
                                                                SourceItemStatus.Delete, "$/Foo/bar.txt", 0, null));

                engine.Update(@"C:\Foo", false, VersionSpec.Latest, delegate(SourceItem item,
                                                                             UpdateAction actionTaken,
                                                                             SourceItemResult result)
                                                                    {
                                                                        callbackItem = item;
                                                                        callbackAction = actionTaken;
                                                                        callbackResult = result;
                                                                    });

                Assert.Equal(SourceItemStatus.Modified, callbackItem.LocalItemStatus);
                Assert.Equal(SourceItemStatus.Delete, callbackItem.RemoteItemStatus);
                Assert.Equal(UpdateAction.None, callbackAction);
                SourceItem resultItem = engine.GetSourceItem(@"C:\Foo\bar.txt");
                Assert.Equal(SourceItemStatus.Modified, resultItem.LocalItemStatus);
                Assert.Equal(4, resultItem.LocalChangesetId);
                Assert.Equal(SourceItemResult.E_WontDeleteFileWithModifications, callbackResult);
            }

            [Fact]
            public void LocalUnmodified()
            {
                SourceItem callbackItem = null;
                UpdateAction callbackAction = UpdateAction.None;
                SourceItemResult callbackResult = SourceItemResult.S_Ok;
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.WriteAllText(@"C:\Foo\bar.txt", "text");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 2, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFile(@"C:\Foo\bar.txt", 3, 4, SourceItemStatus.Unmodified);
                engine.StubStatusWithServer(root,
                                            SourceItem.FromItem(3, ItemType.File,
                                                                SourceItemStatus.Unmodified, SourceItemStatus.Unmodified, @"C:\Foo\bar.txt", null, 4, 0, null,
                                                                SourceItemStatus.Delete, "$/Foo/bar.txt", 0, null));

                engine.Update(@"C:\Foo", false, VersionSpec.Latest, delegate(SourceItem item,
                                                                             UpdateAction actionTaken,
                                                                             SourceItemResult result)
                                                                    {
                                                                        callbackItem = item;
                                                                        callbackAction = actionTaken;
                                                                        callbackResult = result;
                                                                    });

                Assert.Equal(SourceItemStatus.Unmodified, callbackItem.LocalItemStatus);
                Assert.Equal(SourceItemStatus.Delete, callbackItem.RemoteItemStatus);
                Assert.Equal(UpdateAction.Deleted, callbackAction);
                Assert.False(engine.FileSystem.FileExists(@"C:\Foo\bar.txt"));
                Assert.False(engine.TfsState.IsFileTracked(@"C:\Foo\bar.txt"));
                Assert.Equal(SourceItemResult.S_Ok, callbackResult);
            }
        }

        public class Update_File_ServerModified
        {
            [Fact]
            public void DownloadedAndTracked()
            {
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.WriteAllText(@"C:\Foo\bar.txt", "Pre-download");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 2, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFile(@"C:\Foo\bar.txt", 3, 4, SourceItemStatus.Unmodified);
                engine.StubStatusWithServer(SourceItem.FromItem(3, ItemType.File,
                                                                SourceItemStatus.Unmodified, SourceItemStatus.Unmodified, @"C:\Foo\bar.txt", null, 4, 0, null,
                                                                SourceItemStatus.Modified, "$/Foo/bar.txt", 20, "dt"));

                engine.Update(@"C:\Foo\bar.txt", false, VersionSpec.Latest, null);

                SourceItem item = engine.TfsState.GetSourceItem(@"C:\Foo\bar.txt");
                Assert.Equal(20, item.LocalChangesetId);
                Assert.Equal(SourceItemStatus.Unmodified, item.LocalItemStatus);
                Assert.Equal("Downloaded from dt", engine.FileSystem.ReadAllText(@"C:\Foo\bar.txt"));
            }

            [Fact]
            public void LocalConflict()
            {
                SourceItem callbackItem = null;
                UpdateAction callbackAction = UpdateAction.None;
                SourceItemResult callbackResult = SourceItemResult.S_Ok;
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.WriteAllText(@"C:\Foo\bar.txt", "contents");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 2, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFile(@"C:\Foo\bar.txt", 3, 4, SourceItemStatus.Unmodified);
                engine.TfsState.MarkFileAsConflicted(@"C:\Foo\bar.txt", @"C:\Foo\bar.txt", 5);
                engine.StubStatusWithServer(root,
                                            SourceItem.FromItem(3, ItemType.File,
                                                                SourceItemStatus.Conflict, SourceItemStatus.Conflict, @"C:\Foo\bar.txt", @"C:\Foo\_tfs\text-base\bar.txt.tfs-base", 4, 5, @"C:\Foo\_tfs\text-base\bar.txt.tfs-conflict",
                                                                SourceItemStatus.Modified, "$/Foo/bar.txt", 20, "dt"));

                engine.Update(@"C:\Foo", false, VersionSpec.Latest, delegate(SourceItem item,
                                                                             UpdateAction actionTaken,
                                                                             SourceItemResult result)
                                                                    {
                                                                        callbackItem = item;
                                                                        callbackAction = actionTaken;
                                                                        callbackResult = result;
                                                                    });

                Assert.Equal(SourceItemStatus.Conflict, callbackItem.LocalItemStatus);
                Assert.Equal(SourceItemStatus.Modified, callbackItem.RemoteItemStatus);
                Assert.Equal(UpdateAction.None, callbackAction);
                SourceItem resultItem = engine.GetSourceItem(@"C:\Foo\bar.txt");
                Assert.Equal(SourceItemStatus.Conflict, resultItem.LocalItemStatus);
                Assert.Equal(4, resultItem.LocalChangesetId);
                Assert.Equal("contents", engine.FileSystem.ReadAllText(@"C:\Foo\bar.txt"));
                Assert.False(engine.FileSystem.FileExists(@"C:\Foo\bar.txt.r4"));
                Assert.False(engine.FileSystem.FileExists(@"C:\Foo\bar.txt.r20"));
                Assert.Equal(SourceItemResult.E_AlreadyConflicted, callbackResult);
            }

            [Fact]
            public void LocalDelete()
            {
                SourceItem callbackItem = null;
                UpdateAction callbackAction = UpdateAction.None;
                SourceItemResult callbackResult = SourceItemResult.S_Ok;
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 2, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFile(@"C:\Foo\bar.txt", 3, 4, SourceItemStatus.Delete);
                engine.StubStatusWithServer(root,
                                            SourceItem.FromItem(3, ItemType.File,
                                                                SourceItemStatus.Delete, SourceItemStatus.Delete, @"C:\Foo\bar.txt", @"C:\Foo\_tfs\text-base\bar.txt.tfs-base", 4, 0, null,
                                                                SourceItemStatus.Modified, "$/Foo/bar.txt", 20, "dt"));

                engine.Update(@"C:\Foo", false, VersionSpec.Latest, delegate(SourceItem item,
                                                                             UpdateAction actionTaken,
                                                                             SourceItemResult result)
                                                                    {
                                                                        callbackItem = item;
                                                                        callbackAction = actionTaken;
                                                                        callbackResult = result;
                                                                    });

                Assert.Equal(SourceItemStatus.Delete, callbackItem.LocalItemStatus);
                Assert.Equal(SourceItemStatus.Modified, callbackItem.RemoteItemStatus);
                Assert.Equal(UpdateAction.Updated, callbackAction);
                SourceItem resultItem = engine.GetSourceItem(@"C:\Foo\bar.txt");
                Assert.Equal(SourceItemStatus.Delete, resultItem.LocalItemStatus);
                Assert.Equal(20, resultItem.LocalChangesetId);
                Assert.Equal("Downloaded from dt", engine.FileSystem.ReadAllText(@"C:\Foo\bar.txt"));
                Assert.False(engine.FileSystem.FileExists(@"C:\Foo\bar.txt.r4"));
                Assert.False(engine.FileSystem.FileExists(@"C:\Foo\bar.txt.r20"));
                Assert.Equal(SourceItemResult.S_Ok, callbackResult);
            }

            [Fact]
            public void LocalMissing()
            {
                SourceItem callbackItem = null;
                UpdateAction callbackAction = UpdateAction.None;
                SourceItemResult callbackResult = SourceItemResult.S_Ok;
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.WriteAllText(@"C:\Foo\bar.txt", "the file text");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 2, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFile(@"C:\Foo\bar.txt", 3, 4, SourceItemStatus.Unmodified);
                engine.FileSystem.DeleteFile(@"C:\Foo\bar.txt");
                engine.StubStatusWithServer(root,
                                            SourceItem.FromItem(3, ItemType.File,
                                                                SourceItemStatus.Missing, SourceItemStatus.Unmodified, @"C:\Foo\bar.txt", @"C:\Foo\_tfs\text-base\bar.txt.tfs-base", 4, 0, null,
                                                                SourceItemStatus.Modified, "$/Foo/bar.txt", 20, "dt"));

                engine.Update(@"C:\Foo", false, VersionSpec.Latest, delegate(SourceItem item,
                                                                             UpdateAction actionTaken,
                                                                             SourceItemResult result)
                                                                    {
                                                                        callbackItem = item;
                                                                        callbackAction = actionTaken;
                                                                        callbackResult = result;
                                                                    });

                Assert.Equal(SourceItemStatus.Missing, callbackItem.LocalItemStatus);
                Assert.Equal(SourceItemStatus.Modified, callbackItem.RemoteItemStatus);
                Assert.Equal(UpdateAction.Updated, callbackAction);
                SourceItem resultItem = engine.TfsState.GetSourceItem(@"C:\Foo\bar.txt");
                Assert.Equal(3, resultItem.ItemId);
                Assert.Equal(ItemType.File, resultItem.ItemType);
                Assert.Equal(20, resultItem.LocalChangesetId);
                Assert.Equal(SourceItemStatus.Unmodified, resultItem.LocalItemStatus);
                Assert.Equal(@"C:\Foo\bar.txt", resultItem.LocalName);
                Assert.Equal("Downloaded from dt", engine.FileSystem.ReadAllText(@"C:\Foo\bar.txt"));
                Assert.Equal(SourceItemResult.S_Ok, callbackResult);
            }

            [Fact]
            public void LocalModified_Conflict()
            {
                SourceItem callbackItem = null;
                UpdateAction callbackAction = UpdateAction.None;
                SourceItemResult callbackResult = SourceItemResult.S_Ok;
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.WriteAllText(@"C:\Foo\bar.txt", "contents");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 2, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFile(@"C:\Foo\bar.txt", 3, 4, SourceItemStatus.Unmodified);
                engine.FileSystem.WriteAllText(@"C:\Foo\bar.txt", "locally updated contents");
                engine.StubStatusWithServer(root,
                                            SourceItem.FromItem(3, ItemType.File,
                                                                SourceItemStatus.Modified, SourceItemStatus.Modified, @"C:\Foo\bar.txt", @"C:\Foo\_tfs\text-base\bar.txt.tfs-base", 4, 0, null,
                                                                SourceItemStatus.Modified, "$/Foo/bar.txt", 20, "dt"));

                engine.Update(@"C:\Foo", false, VersionSpec.Latest, delegate(SourceItem item,
                                                                             UpdateAction actionTaken,
                                                                             SourceItemResult result)
                                                                    {
                                                                        callbackItem = item;
                                                                        callbackAction = actionTaken;
                                                                        callbackResult = result;
                                                                    });

                Assert.Equal(SourceItemStatus.Modified, callbackItem.LocalItemStatus);
                Assert.Equal(SourceItemStatus.Modified, callbackItem.RemoteItemStatus);
                Assert.Equal(UpdateAction.Conflicted, callbackAction);
                SourceItem resultItem = engine.GetSourceItem(@"C:\Foo\bar.txt");
                Assert.Equal(SourceItemStatus.Conflict, resultItem.LocalItemStatus);
                Assert.Equal(4, resultItem.LocalChangesetId);
                Assert.Equal(20, resultItem.LocalConflictChangesetId);
                Assert.Equal("contents", engine.FileSystem.ReadAllText(@"C:\Foo\bar.txt.r4"));
                Assert.Equal("Downloaded from dt", engine.FileSystem.ReadAllText(@"C:\Foo\bar.txt.r20"));
                Assert.Equal("Downloaded from dt", engine.FileSystem.ReadAllText(@"C:\Foo\_tfs\text-base\bar.txt.tfs-conflict"));
                Assert.Equal("locally updated contents", engine.FileSystem.ReadAllText(@"C:\Foo\bar.txt"));
                Assert.Equal("locally updated contents", engine.FileSystem.ReadAllText(@"C:\Foo\bar.txt.mine"));
                Assert.NotEqual(FileAttributes.ReadOnly, engine.FileSystem.GetAttributes(@"C:\Foo\bar.txt.r4") & FileAttributes.ReadOnly);
                Assert.Equal(SourceItemResult.S_Ok, callbackResult);
            }

            [Fact(Skip="Automerge is temporarily disabled")]
            public void LocalModified_Mergeable()
            {
                SourceItem callbackItem = null;
                UpdateAction callbackAction = UpdateAction.None;
                SourceItemResult callbackResult = SourceItemResult.S_Ok;
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.WriteAllText(@"C:\Foo\bar.txt",
                                               @"Line 1
Line 2
Line 3");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 2, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFile(@"C:\Foo\bar.txt", 3, 4, SourceItemStatus.Unmodified);
                engine.FileSystem.WriteAllText(@"C:\Foo\bar.txt",
                                               @"Line 1
Line 2
Line 2a
Line 3");
                engine.WebTransferService.Download__Text =
                    @"Line 1
Line 1a
Line 2
Line 3";
                string expectedOutput =
                    @"Line 1
Line 1a
Line 2
Line 2a
Line 3";
                engine.StubStatusWithServer(root,
                                            SourceItem.FromItem(3, ItemType.File,
                                                                SourceItemStatus.Modified, SourceItemStatus.Modified, @"C:\Foo\bar.txt", null, 4, 0, null,
                                                                SourceItemStatus.Modified, "$/Foo/bar.txt", 20, "dt"));

                engine.Update(@"C:\Foo", false, VersionSpec.Latest, delegate(SourceItem item,
                                                                             UpdateAction actionTaken,
                                                                             SourceItemResult result)
                                                                    {
                                                                        callbackItem = item;
                                                                        callbackAction = actionTaken;
                                                                        callbackResult = result;
                                                                    });

                Assert.Equal(SourceItemStatus.Modified, callbackItem.LocalItemStatus);
                Assert.Equal(SourceItemStatus.Modified, callbackItem.RemoteItemStatus);
                Assert.Equal(UpdateAction.Merged, callbackAction);
                SourceItem resultItem = engine.GetSourceItem(@"C:\Foo\bar.txt");
                Assert.Equal(SourceItemStatus.Modified, resultItem.LocalItemStatus);
                Assert.Equal(20, resultItem.LocalChangesetId);
                Assert.Equal(expectedOutput, engine.FileSystem.ReadAllText(@"C:\Foo\bar.txt"));
                Assert.Equal(SourceItemResult.S_Ok, callbackResult);
            }

            [Fact]
            public void LocalUnmodified()
            {
                SourceItem callbackItem = null;
                UpdateAction callbackAction = UpdateAction.None;
                SourceItemResult callbackResult = SourceItemResult.S_Ok;
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.WriteAllText(@"C:\Foo\bar.txt", "contents");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 2, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFile(@"C:\Foo\bar.txt", 3, 4, SourceItemStatus.Unmodified);
                engine.StubStatusWithServer(root,
                                            SourceItem.FromItem(3, ItemType.File,
                                                                SourceItemStatus.Unmodified, SourceItemStatus.Unmodified, @"C:\Foo\bar.txt", null, 4, 0, null,
                                                                SourceItemStatus.Modified, "$/Foo/bar.txt", 20, "dt"));

                engine.Update(@"C:\Foo", false, VersionSpec.Latest, delegate(SourceItem item,
                                                                             UpdateAction actionTaken,
                                                                             SourceItemResult result)
                                                                    {
                                                                        callbackItem = item;
                                                                        callbackAction = actionTaken;
                                                                        callbackResult = result;
                                                                    });

                Assert.Equal(SourceItemStatus.Unmodified, callbackItem.LocalItemStatus);
                Assert.Equal(SourceItemStatus.Modified, callbackItem.RemoteItemStatus);
                Assert.Equal(UpdateAction.Updated, callbackAction);
                Assert.False(engine.FileSystem.FileExists(@"C:\Foo\bar.txt.r4"));
                Assert.False(engine.FileSystem.FileExists(@"C:\Foo\bar.txt.r20"));
                Assert.Equal(SourceItemResult.S_Ok, callbackResult);
            }
        }

        public class Update_File_ServerUnmodified
        {
            [Fact]
            public void LocalMissing()
            {
                SourceItem callbackItem = null;
                UpdateAction callbackAction = UpdateAction.None;
                SourceItemResult callbackResult = SourceItemResult.S_Ok;
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.WriteAllText(@"C:\Foo\bar.txt", "the file text");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 2, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFile(@"C:\Foo\bar.txt", 3, 4, SourceItemStatus.Unmodified);
                engine.FileSystem.DeleteFile(@"C:\Foo\bar.txt");
                engine.StubStatusWithServer(root,
                                            SourceItem.FromItem(3, ItemType.File,
                                                                SourceItemStatus.Missing, SourceItemStatus.Unmodified, @"C:\Foo\bar.txt", @"C:\Foo\_tfs\text-base\bar.txt.tfs-base", 4, 0, null,
                                                                SourceItemStatus.Unmodified, "$/Foo/bar.txt", 4, "dt"));

                engine.Update(@"C:\Foo", false, VersionSpec.Latest, delegate(SourceItem item,
                                                                             UpdateAction actionTaken,
                                                                             SourceItemResult result)
                                                                    {
                                                                        callbackItem = item;
                                                                        callbackAction = actionTaken;
                                                                        callbackResult = result;
                                                                    });

                Assert.Equal(SourceItemStatus.Missing, callbackItem.LocalItemStatus);
                Assert.Equal(SourceItemStatus.Unmodified, callbackItem.RemoteItemStatus);
                Assert.Equal(UpdateAction.Reverted, callbackAction);
                SourceItem resultItem = engine.TfsState.GetSourceItem(@"C:\Foo\bar.txt");
                Assert.Equal(3, resultItem.ItemId);
                Assert.Equal(ItemType.File, resultItem.ItemType);
                Assert.Equal(4, resultItem.LocalChangesetId);
                Assert.Equal(SourceItemStatus.Unmodified, resultItem.LocalItemStatus);
                Assert.Equal(@"C:\Foo\bar.txt", resultItem.LocalName);
                Assert.Equal("the file text", engine.FileSystem.ReadAllText(@"C:\Foo\bar.txt"));
                Assert.Equal(SourceItemResult.S_Ok, callbackResult);
            }
        }

        public class Update_Folder_ServerAdd
        {
            [Fact]
            public void CreatedAndTracked()
            {
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 2, SourceItemStatus.Unmodified);
                engine.StubStatusWithServer(root,
                                            SourceItem.FromItem(3, ItemType.Folder,
                                                                SourceItemStatus.None, SourceItemStatus.None, @"C:\Foo\Bar", null, 0, 0, null,
                                                                SourceItemStatus.Add, "$/Foo/Bar", 4, null));

                engine.Update(@"C:\Foo", false, VersionSpec.Latest, null);

                Assert.True(engine.FileSystem.DirectoryExists(@"C:\Foo\Bar"));
                Assert.True(engine.TfsState.IsFolderTracked(@"C:\Foo\Bar"));
                TfsFolderInfo folderInfo = engine.TfsState.GetFolderInfo(@"C:\Foo\Bar");
                Assert.Equal("http://tfsUrl", folderInfo.TfsUrl);
                Assert.Equal("$/Foo/Bar/", folderInfo.ServerPath);
            }

            [Fact]
            public void LocalAdded()
            {
                SourceItem callbackItem = null;
                UpdateAction callbackAction = UpdateAction.None;
                SourceItemResult callbackResult = SourceItemResult.S_Ok;
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.EnsurePath(@"C:\Foo\Bar");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 2, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo/Bar", @"C:\Foo\Bar", 0, 0, SourceItemStatus.Add);
                engine.StubStatusWithServer(root,
                                            SourceItem.FromItem(3, ItemType.Folder,
                                                                SourceItemStatus.Add, SourceItemStatus.Add, @"C:\Foo\Bar", null, 0, 0, null,
                                                                SourceItemStatus.Add, "$/Foo/Bar", 4, null));

                engine.Update(@"C:\Foo", false, VersionSpec.Latest, delegate(SourceItem item,
                                                                             UpdateAction actionTaken,
                                                                             SourceItemResult result)
                                                                    {
                                                                        callbackItem = item;
                                                                        callbackAction = actionTaken;
                                                                        callbackResult = result;
                                                                    });

                Assert.Equal(SourceItemStatus.Add, callbackItem.LocalItemStatus);
                Assert.Equal(SourceItemStatus.Add, callbackItem.RemoteItemStatus);
                Assert.Equal(UpdateAction.Added, callbackAction);
                SourceItem resultItem = engine.TfsState.GetSourceItem(@"C:\Foo\Bar");
                Assert.Equal(3, resultItem.ItemId);
                Assert.Equal(ItemType.Folder, resultItem.ItemType);
                Assert.Equal(4, resultItem.LocalChangesetId);
                Assert.Equal(SourceItemStatus.Unmodified, resultItem.LocalItemStatus);
                Assert.Equal(@"C:\Foo\Bar", resultItem.LocalName);
                Assert.Equal(SourceItemResult.S_Ok, callbackResult);
            }

            [Fact]
            public void LocalNotPresent()
            {
                SourceItem callbackItem = null;
                UpdateAction callbackAction = UpdateAction.None;
                SourceItemResult callbackResult = SourceItemResult.S_Ok;
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 2, SourceItemStatus.Unmodified);
                engine.StubStatusWithServer(root,
                                            SourceItem.FromItem(3, ItemType.Folder,
                                                                SourceItemStatus.None, SourceItemStatus.None, @"C:\Foo\Bar", null, 0, 0, null,
                                                                SourceItemStatus.Add, "$/Foo/Bar", 4, null));

                engine.Update(@"C:\Foo", false, VersionSpec.Latest, delegate(SourceItem item,
                                                                             UpdateAction actionTaken,
                                                                             SourceItemResult result)
                                                                    {
                                                                        callbackItem = item;
                                                                        callbackAction = actionTaken;
                                                                        callbackResult = result;
                                                                    });

                Assert.Equal(SourceItemStatus.None, callbackItem.LocalItemStatus);
                Assert.Equal(SourceItemStatus.Add, callbackItem.RemoteItemStatus);
                Assert.Equal(UpdateAction.Added, callbackAction);
                SourceItem resultItem = engine.TfsState.GetSourceItem(@"C:\Foo\Bar");
                Assert.Equal(3, resultItem.ItemId);
                Assert.Equal(ItemType.Folder, resultItem.ItemType);
                Assert.Equal(4, resultItem.LocalChangesetId);
                Assert.Equal(SourceItemStatus.Unmodified, resultItem.LocalItemStatus);
                Assert.Equal(@"C:\Foo\Bar", resultItem.LocalName);
                Assert.Equal(SourceItemResult.S_Ok, callbackResult);
            }

            [Fact]
            public void LocalUnversioned()
            {
                SourceItem callbackItem = null;
                UpdateAction callbackAction = UpdateAction.None;
                SourceItemResult callbackResult = SourceItemResult.S_Ok;
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.EnsurePath(@"C:\Foo\Bar");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 2, SourceItemStatus.Unmodified);
                engine.StubStatusWithServer(root,
                                            SourceItem.FromItem(3, ItemType.Folder,
                                                                SourceItemStatus.Unversioned, SourceItemStatus.Unversioned, @"C:\Foo\Bar", null, 0, 0, null,
                                                                SourceItemStatus.Add, "$/Foo/Bar", 4, null));

                engine.Update(@"C:\Foo", false, VersionSpec.Latest, delegate(SourceItem item,
                                                                             UpdateAction actionTaken,
                                                                             SourceItemResult result)
                                                                    {
                                                                        callbackItem = item;
                                                                        callbackAction = actionTaken;
                                                                        callbackResult = result;
                                                                    });

                Assert.Equal(SourceItemStatus.Unversioned, callbackItem.LocalItemStatus);
                Assert.Equal(SourceItemStatus.Add, callbackItem.RemoteItemStatus);
                Assert.Equal(UpdateAction.Added, callbackAction);
                SourceItem resultItem = engine.TfsState.GetSourceItem(@"C:\Foo\Bar");
                Assert.Equal(3, resultItem.ItemId);
                Assert.Equal(ItemType.Folder, resultItem.ItemType);
                Assert.Equal(4, resultItem.LocalChangesetId);
                Assert.Equal(SourceItemStatus.Unmodified, resultItem.LocalItemStatus);
                Assert.Equal(@"C:\Foo\Bar", resultItem.LocalName);
                Assert.Equal(SourceItemResult.S_Ok, callbackResult);
            }
        }

        public class Update_Folder_ServerDelete
        {
            [Fact]
            public void LocalMissing()
            {
                SourceItem callbackItem = null;
                UpdateAction callbackAction = UpdateAction.None;
                SourceItemResult callbackResult = SourceItemResult.S_Ok;
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.EnsurePath(@"C:\Foo\Bar");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 2, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo/Bar", @"C:\Foo\Bar", 3, 4, SourceItemStatus.Unmodified);
                engine.FileSystem.DeleteDirectory(@"C:\Foo\Bar", true);
                engine.StubStatusWithServer(root,
                                            SourceItem.FromItem(3, ItemType.Folder,
                                                                SourceItemStatus.Missing, SourceItemStatus.Unmodified, @"C:\Foo\Bar", null, 4, 0, null,
                                                                SourceItemStatus.Delete, "$/Foo/Bar", 4, null));

                engine.Update(@"C:\Foo", true, VersionSpec.Latest, delegate(SourceItem item,
                                                                            UpdateAction actionTaken,
                                                                            SourceItemResult result)
                                                                   {
                                                                       callbackItem = item;
                                                                       callbackAction = actionTaken;
                                                                       callbackResult = result;
                                                                   });

                Assert.Equal(SourceItemStatus.Missing, callbackItem.LocalItemStatus);
                Assert.Equal(SourceItemStatus.Delete, callbackItem.RemoteItemStatus);
                Assert.Equal(UpdateAction.Deleted, callbackAction);
                Assert.False(engine.TfsState.IsFolderTracked(@"C:\Foo\Bar"));
                Assert.False(engine.FileSystem.DirectoryExists(@"C:\Foo\Bar"));
                Assert.Equal(SourceItemResult.S_Ok, callbackResult);
            }

            [Fact]
            public void LocalUnmodified_DirectoryEmpty()
            {
                SourceItem callbackItem = null;
                UpdateAction callbackAction = UpdateAction.None;
                SourceItemResult callbackResult = SourceItemResult.S_Ok;
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.EnsurePath(@"C:\Foo\Bar");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 2, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo/Bar", @"C:\Foo\Bar", 3, 4, SourceItemStatus.Unmodified);
                engine.StubStatusWithServer(root,
                                            SourceItem.FromItem(3, ItemType.Folder,
                                                                SourceItemStatus.Unmodified, SourceItemStatus.Unmodified, @"C:\Foo\Bar", null, 4, 0, null,
                                                                SourceItemStatus.Delete, "$/Foo/Bar", 4, null));

                engine.Update(@"C:\Foo", false, VersionSpec.Latest, delegate(SourceItem item,
                                                                             UpdateAction actionTaken,
                                                                             SourceItemResult result)
                                                                    {
                                                                        callbackItem = item;
                                                                        callbackAction = actionTaken;
                                                                        callbackResult = result;
                                                                    });

                Assert.Equal(SourceItemStatus.Unmodified, callbackItem.LocalItemStatus);
                Assert.Equal(SourceItemStatus.Delete, callbackItem.RemoteItemStatus);
                Assert.Equal(UpdateAction.Deleted, callbackAction);
                Assert.False(engine.TfsState.IsFolderTracked(@"C:\Foo\Bar"));
                Assert.False(engine.FileSystem.DirectoryExists(@"C:\Foo\Bar"));
                Assert.Equal(SourceItemResult.S_Ok, callbackResult);
            }

            [Fact]
            public void LocalUnmodified_TrackedFiles()
            {
                SourceItem callbackItem = null;
                UpdateAction callbackAction = UpdateAction.None;
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.EnsurePath(@"C:\Foo\Bar");
                engine.FileSystem.WriteAllText(@"C:\Foo\Bar\tracked.txt", "text");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 2, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo/Bar", @"C:\Foo\Bar", 3, 4, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFile(@"C:\Foo\Bar\tracked.txt", 5, 6, SourceItemStatus.Unmodified);
                engine.StubStatusWithServer(root,
                                            SourceItem.FromItem(3, ItemType.Folder,
                                                                SourceItemStatus.Unmodified, SourceItemStatus.Unmodified, @"C:\Foo\Bar", null, 4, 0, null,
                                                                SourceItemStatus.Delete, "$/Foo/Bar", 4, null),
                                            SourceItem.FromItem(5, ItemType.File,
                                                                SourceItemStatus.Unmodified, SourceItemStatus.Unmodified, @"C:\Foo\Bar\tracked.txt", @"C:\Foo\bar\_tfs\text-base\tracked.txt.tfs-base", 6, 0, null,
                                                                SourceItemStatus.Delete, "$/Foo/Bar/tracked.txt", 0, null));

                engine.Update(@"C:\Foo", true, VersionSpec.Latest, delegate(SourceItem item,
                                                                            UpdateAction actionTaken,
                                                                            SourceItemResult result)
                                                                   {
                                                                       callbackItem = item;
                                                                       callbackAction = actionTaken;
                                                                   });

                Assert.Equal(SourceItemStatus.Unmodified, callbackItem.LocalItemStatus);
                Assert.Equal(SourceItemStatus.Delete, callbackItem.RemoteItemStatus);
                Assert.Equal(UpdateAction.Deleted, callbackAction);
                Assert.False(engine.TfsState.IsFolderTracked(@"C:\Foo\Bar"));
                Assert.False(engine.FileSystem.DirectoryExists(@"C:\Foo\Bar"));
            }

            [Fact]
            public void LocalUnmodified_UnversionedFiles()
            {
                SourceItem callbackItem = null;
                UpdateAction callbackAction = UpdateAction.None;
                SourceItemResult callbackResult = SourceItemResult.S_Ok;
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.EnsurePath(@"C:\Foo\Bar");
                engine.FileSystem.WriteAllText(@"C:\Foo\Bar\unversioned.txt", "text");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 2, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo/Bar", @"C:\Foo\Bar", 3, 4, SourceItemStatus.Unmodified);
                engine.StubStatusWithServer(root,
                                            SourceItem.FromItem(3, ItemType.Folder,
                                                                SourceItemStatus.Unmodified, SourceItemStatus.Unmodified, @"C:\Foo\Bar", null, 4, 0, null,
                                                                SourceItemStatus.Delete, "$/Foo/Bar", 4, null),
                                            SourceItem.FromLocalFile(0,
                                                                     SourceItemStatus.Unversioned, SourceItemStatus.Unversioned, @"C:\Foo\unversioned.txt", null, 0, 0, null));

                engine.Update(@"C:\Foo", false, VersionSpec.Latest, delegate(SourceItem item,
                                                                             UpdateAction actionTaken,
                                                                             SourceItemResult result)
                                                                    {
                                                                        callbackItem = item;
                                                                        callbackAction = actionTaken;
                                                                        callbackResult = result;
                                                                    });

                Assert.Equal(SourceItemStatus.Unmodified, callbackItem.LocalItemStatus);
                Assert.Equal(SourceItemStatus.Delete, callbackItem.RemoteItemStatus);
                Assert.Equal(UpdateAction.Deleted, callbackAction);
                Assert.False(engine.TfsState.IsFolderTracked(@"C:\Foo\Bar"));
                Assert.True(engine.FileSystem.DirectoryExists(@"C:\Foo\Bar"));
                Assert.True(engine.FileSystem.FileExists(@"C:\Foo\Bar\unversioned.txt"));
                Assert.Equal(SourceItemResult.S_Ok, callbackResult);
            }
        }

        public class Update_Folder_ServerModified
        {
            [Fact]
            public void LocalDelete()
            {
                SourceItem callbackItem = null;
                UpdateAction callbackAction = UpdateAction.None;
                SourceItemResult callbackResult = SourceItemResult.S_Ok;
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.EnsurePath(@"C:\Foo\Bar");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 2, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo/Bar", @"C:\Foo\Bar", 3, 4, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo/Bar", @"C:\Foo\Bar", 3, 4, SourceItemStatus.Delete);
                engine.StubStatusWithServer(root,
                                            SourceItem.FromItem(3, ItemType.Folder,
                                                                SourceItemStatus.Delete, SourceItemStatus.Delete, @"C:\Foo\Bar", null, 4, 0, null,
                                                                SourceItemStatus.Modified, "$/Foo/Bar", 20, null));

                engine.Update(@"C:\Foo", false, VersionSpec.Latest, delegate(SourceItem item,
                                                                             UpdateAction actionTaken,
                                                                             SourceItemResult result)
                                                                    {
                                                                        callbackItem = item;
                                                                        callbackAction = actionTaken;
                                                                        callbackResult = result;
                                                                    });

                Assert.Equal(SourceItemStatus.Delete, callbackItem.LocalItemStatus);
                Assert.Equal(SourceItemStatus.Modified, callbackItem.RemoteItemStatus);
                Assert.Equal(UpdateAction.Updated, callbackAction);
                SourceItem resultItem = engine.TfsState.GetSourceItem(@"C:\Foo\Bar");
                Assert.Equal(3, resultItem.ItemId);
                Assert.Equal(ItemType.Folder, resultItem.ItemType);
                Assert.Equal(20, resultItem.LocalChangesetId);
                Assert.Equal(SourceItemStatus.Delete, resultItem.LocalItemStatus);
                Assert.Equal(@"C:\Foo\Bar", resultItem.LocalName);
                Assert.Equal(SourceItemResult.S_Ok, callbackResult);
            }

            [Fact]
            public void LocalUnmodified()
            {
                SourceItem callbackItem = null;
                UpdateAction callbackAction = UpdateAction.None;
                SourceItemResult callbackResult = SourceItemResult.S_Ok;
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.EnsurePath(@"C:\Foo\Bar");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 2, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo/Bar", @"C:\Foo\Bar", 3, 4, SourceItemStatus.Unmodified);
                engine.StubStatusWithServer(root,
                                            SourceItem.FromItem(3, ItemType.Folder,
                                                                SourceItemStatus.Unmodified, SourceItemStatus.Unmodified, @"C:\Foo\Bar", null, 4, 0, null,
                                                                SourceItemStatus.Modified, "$/Foo/Bar", 20, null));

                engine.Update(@"C:\Foo", false, VersionSpec.Latest, delegate(SourceItem item,
                                                                             UpdateAction actionTaken,
                                                                             SourceItemResult result)
                                                                    {
                                                                        callbackItem = item;
                                                                        callbackAction = actionTaken;
                                                                        callbackResult = result;
                                                                    });

                Assert.Equal(SourceItemStatus.Unmodified, callbackItem.LocalItemStatus);
                Assert.Equal(SourceItemStatus.Modified, callbackItem.RemoteItemStatus);
                Assert.Equal(UpdateAction.Updated, callbackAction);
                SourceItem resultItem = engine.TfsState.GetSourceItem(@"C:\Foo\Bar");
                Assert.Equal(3, resultItem.ItemId);
                Assert.Equal(ItemType.Folder, resultItem.ItemType);
                Assert.Equal(20, resultItem.LocalChangesetId);
                Assert.Equal(SourceItemStatus.Unmodified, resultItem.LocalItemStatus);
                Assert.Equal(@"C:\Foo\Bar", resultItem.LocalName);
                Assert.Equal(SourceItemResult.S_Ok, callbackResult);
            }
        }

        public class Update_Folder_ServerUnmodified
        {
            [Fact]
            public void LocalMissing()
            {
                SourceItem callbackItem = null;
                UpdateAction callbackAction = UpdateAction.None;
                SourceItemResult callbackResult = SourceItemResult.S_Ok;
                TestableTfsEngine engine = TestableTfsEngine.Create();
                engine.FileSystem.EnsurePath(@"C:\Foo");
                engine.FileSystem.EnsurePath(@"C:\Foo\Bar");
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo", @"C:\Foo", 1, 2, SourceItemStatus.Unmodified);
                engine.TfsState.TrackFolder("http://tfsUrl", "$/Foo/Bar", @"C:\Foo\Bar", 3, 4, SourceItemStatus.Unmodified);
                engine.FileSystem.DeleteDirectory(@"C:\Foo\Bar", true);
                engine.StubStatusWithServer(root,
                                            SourceItem.FromItem(3, ItemType.Folder,
                                                                SourceItemStatus.Missing, SourceItemStatus.Unmodified, @"C:\Foo\Bar", null, 4, 0, null,
                                                                SourceItemStatus.Unmodified, "$/Foo/Bar", 4, null));

                engine.Update(@"C:\Foo", false, VersionSpec.Latest, delegate(SourceItem item,
                                                                             UpdateAction actionTaken,
                                                                             SourceItemResult result)
                                                                    {
                                                                        callbackItem = item;
                                                                        callbackAction = actionTaken;
                                                                        callbackResult = result;
                                                                    });

                Assert.Equal(SourceItemStatus.Missing, callbackItem.LocalItemStatus);
                Assert.Equal(SourceItemStatus.Unmodified, callbackItem.RemoteItemStatus);
                Assert.Equal(UpdateAction.Updated, callbackAction);
                SourceItem resultItem = engine.TfsState.GetSourceItem(@"C:\Foo\Bar");
                Assert.Equal(3, resultItem.ItemId);
                Assert.Equal(ItemType.Folder, resultItem.ItemType);
                Assert.Equal(4, resultItem.LocalChangesetId);
                Assert.Equal(SourceItemStatus.Unmodified, resultItem.LocalItemStatus);
                Assert.Equal(@"C:\Foo\Bar", resultItem.LocalName);
                Assert.Equal(SourceItemResult.S_Ok, callbackResult);
            }
        }
    }
}